# coding:utf-8
"""
    @project: selenium_utls
    @Author：caicaizi
    @file： base_web_driver.py
    @date：2024/1/13 10:16
"""
import time
from selenium import webdriver
from selenium.webdriver import ActionChains
from selenium.webdriver.common.by import By
from selenium.webdriver.remote.webdriver import WebElement, WebDriver
from selenium.webdriver.support.select import Select
from selenium.webdriver.support.wait import WebDriverWait

from selenium.webdriver.chrome.service import Service as ChromeServer
from selenium.webdriver.firefox.service import Service as FirefoxServer
from selenium.webdriver.edge.service import Service as EdgeServer
from webdriver_manager.chrome import ChromeDriverManager
from webdriver_manager.firefox import GeckoDriverManager
from webdriver_manager.microsoft import EdgeChromiumDriverManager


class BaseWebDriver:
    """浏览器驱动类"""

    def __init__(self, driver: WebDriver = None, browser_type: str = 'chrome'):
        self.flag = 1  # 函数执行标记，实现条件流程控制:1表示执行，0表示不执行
        self.relations = {}  # 存储关联数据
        self.locator_methods = {'xpath': By.XPATH,
                                'id': By.ID,
                                'class': By.CLASS_NAME,
                                'tag_name': By.TAG_NAME,
                                'css': By.CSS_SELECTOR,
                                'link_text': By.LINK_TEXT,
                                'partial_link_text': By.PARTIAL_LINK_TEXT,
                                'name': By.NAME
                                }   # 元素定位方式
        self.browser_type = browser_type    # 浏览器类型
        if driver is None:  # 初始化浏览器驱动
            self.__init_driver()
        else:
            self.driver: WebDriver = driver

    def __init_driver(self):
        """初始化浏览器驱动"""
        if self.browser_type == 'chrome':
            service = ChromeServer(executable_path=ChromeDriverManager().install())
            self.driver: WebDriver = webdriver.Chrome(service=service)
        elif self.browser_type == 'firefox':
            service = FirefoxServer(executable_path=GeckoDriverManager().install())
            self.driver: WebDriver = webdriver.Firefox(service=service)
        elif self.browser_type == 'edge':
            service = EdgeServer(executable_path=EdgeChromiumDriverManager().install())
            self.driver: WebDriver = webdriver.Edge(service=service)
        self.driver.maximize_window()
        self.driver.implicitly_wait(5)

    # 浏览器操作
    def open_url(self, url):
        """
        打开网址
        :param url: 目标网址url
        """
        self.driver.get(url=url)

    def quit(self):
        """关闭浏览器"""
        self.driver.quit()

    # 定位元素
    def get_element(self, by, pattern) -> WebElement:
        """
        定位元素
        :param by: 定位方式
        :param pattern: 定位表达式
        :return:页面元素
        """
        wait = WebDriverWait(self.driver, 15)
        element = wait.until(lambda x: x.find_element(self.locator_methods[by], pattern))
        return element

    def get_elements(self, by, pattern) -> list[WebElement]:
        """
        定位元素
        :param by: 定位方式
        :param pattern: 定位表达式
        :return:页面元素
        """
        wait = WebDriverWait(self.driver, 15)
        elements = wait.until(lambda x: x.find_elements(self.locator_methods[by], pattern))
        return elements

    # 基本操作
    def click(self, by, pattern):
        """点击元素"""
        self.get_element(by, pattern).click()

    def clear(self, by, pattern):
        """清空元素内容"""
        self.get_element(by, pattern).clear()

    def send_keys(self, by, pattern, value):
        """输入"""
        self.get_element(by, pattern).send_keys(value)

    def submit(self, by, pattern):
        """提交表单"""
        self.get_element(by, pattern).submit()

    # 获取内容
    def get_text(self, by, pattern, title=None):
        """获取HTML元素的文本值"""
        text = self.get_element(by, pattern).text
        if title:
            self.relations[title] = text
        return text

    def get_page_source(self, title=None):
        """获取HTML"""
        html = self.driver.page_source
        if title:
            self.relations[title] = html
        return html

    def get_tag_name(self, by, pattern, title=None):
        """获取元素的标签类型"""
        tag_name = self.get_element(by, pattern).tag_name
        if title:
            self.relations[title] = tag_name
        return tag_name

    def get_attribute(self, by, pattern, value):
        """获取元素的HTML属性"""
        attribute = self.get_element(by, pattern).get_attribute(value)
        self.relations[value] = attribute
        return attribute

    def get_css_property(self, by, pattern, value):
        """获取页面元素的CSS属性值"""
        css_property = self.get_element(by=by, pattern=pattern).value_of_css_property(value)
        self.relations[value] = css_property
        return css_property

    def get_driver_title(self):
        driver_title = self.driver.title
        self.relations['driver_title'] = driver_title
        return driver_title

    def get_current_url(self, title=None):
        current_url = self.driver.current_url
        if title:
            self.relations[title] = current_url
        return current_url

    # 多浏览器窗口切换
    def get_window_handles(self):
        handles = self.driver.window_handles
        self.relations['handles'] = handles
        return handles

    def get_current_window_handle(self, title=None):
        handle = self.driver.current_window_handle
        if title:
            self.relations[title] = handle
        return handle

    def switch_to_window(self, handle):
        self.driver.switch_to.window(handle)

    def switch_to_new_window(self):
        handles = self.driver.window_handles
        self.driver.switch_to.window(handles[-1])

    def switch_to_main_window(self):
        handles = self.driver.window_handles
        self.driver.switch_to.window(handles[0])

    # frame窗口切换
    def switch_to_frame(self, by, pattern):
        """切换到当前页面（或IFrame）的下一级指定IFrame中"""
        frame = self.get_element(by, pattern)
        self.driver.switch_to.frame(frame)

    def switch_to_parent_frame(self):
        """切换到当前IFrame的上一级页面（或IFrame）中"""
        self.driver.switch_to.parent_frame()

    # 截图
    def get_screenshot(self, filename):
        """截取浏览器界面"""
        self.driver.get_screenshot_as_file(filename)

    def get_element_screenshot(self, by, pattern, filename):
        """截取元素图片"""
        self.get_element(by, pattern).screenshot(filename)

    # 获取元素状态
    def element_is_selected(self, by, pattern):
        """获取元素的选中状态"""
        is_selected = self.get_element(by, pattern).is_selected()
        return is_selected

    def element_is_enabled(self, by, pattern):
        """获取元素的可编辑状态"""
        is_enabled = self.get_element(by, pattern).is_enabled()
        return is_enabled

    def element_is_displayed(self, by, pattern):
        """获取元素的显示状态"""
        is_displayed = self.get_element(by, pattern).is_displayed()
        return is_displayed

    def element_is_exist(self, by, pattern):
        """判断元素是否存在"""
        self.get_element(by, pattern)

    # 下拉框元素的选项操作
    def select_by_text(self, by, pattern, value):
        """按文本选择下拉框"""
        selectWebElement = Select(self.get_element(by, pattern))
        selectWebElement.select_by_visible_text(value)

    def select_by_index(self, by, pattern, value):
        """按索引选择下拉框"""
        selectWebElement = Select(self.get_element(by, pattern))
        selectWebElement.select_by_index(value)

    def select_by_value(self, by, pattern, value):
        """按选项值选择下拉框"""
        selectWebElement = Select(self.get_element(by, pattern))
        selectWebElement.select_by_value(value)

    def deselect_all(self, by, pattern):
        """取消所有选项"""
        selectWebElement = Select(self.get_element(by, pattern))
        selectWebElement.deselect_all()

    def deselect_by_value(self, by, pattern, value):
        """按选项值取消选项"""
        selectWebElement = Select(self.get_element(by, pattern))
        selectWebElement.deselect_by_value(value)

    def deselect_by_index(self, by, pattern, value):
        """按索引值取消选项"""
        selectWebElement = Select(self.get_element(by, pattern))
        selectWebElement.deselect_by_index(value)

    def deselect_by_visible_text(self, by, pattern, value):
        """按文本取消选项"""
        selectWebElement = Select(self.get_element(by, pattern))
        selectWebElement.deselect_by_visible_text(value)

    # 浏览器窗口操作
    def back(self):
        self.driver.back()

    def forward(self):
        self.driver.forward()

    def refresh(self):
        self.driver.refresh()

    def close(self):
        self.driver.close()

    # 鼠标事件
    def double_click_element(self, by, pattern):
        """双击元素"""
        element = self.get_element(by=by, pattern=pattern)
        ActionChains(self.driver).double_click(element).perform()

    def move_to_element(self, by, pattern):
        """鼠标悬停"""
        element = self.get_element(by=by, pattern=pattern)
        ActionChains(self.driver).move_to_element(element).perform()

    def click_and_hold(self, by, pattern):
        """点击左键并保持"""
        element = self.get_element(by=by, pattern=pattern)
        ActionChains(self.driver).click_and_hold(element).perform()

    # 拖动
    def drag_and_drop_by_offset_x(self, by, pattern, value):
        """向x方向拖动"""
        element = self.get_element(by, pattern)
        ActionChains(self.driver).drag_and_drop_by_offset(element, value, 0).perform()

    def drag_and_drop_by_offset_y(self, by, pattern, value):
        """向y方向拖动"""
        element = self.get_element(by, pattern)
        ActionChains(self.driver).drag_and_drop_by_offset(element, 0, value).perform()

    def drag_and_drop_by_offset(self, by, pattern, **value):
        """向xy方向拖动"""
        element = self.get_element(by, pattern)
        ActionChains(self.driver).drag_and_drop_by_offset(element, **value).perform()

    # 执行js脚本
    def execute_script(self, script):
        self.driver.execute_script(script)

    # 断言
    def assert_(self):
        pass

    # 验证
    def verify(self):
        pass

    # 条件流程控制
    def if_ctrl(self, condition):
        if not condition:
            self.flag = 0

    def end_ctrl(self):
        self.flag = 1


if __name__ == '__main__':
    browser_type = 'edge'
    browser_driver = BaseWebDriver(browser_type=browser_type)
    browser_driver.open_url('https://www.baidu.com/')
    time.sleep(3)
    browser_driver.send_keys('xpath', '//*[@id="kw"]', 'hello world\n')
    time.sleep(3)
    browser_driver.double_click_element('xpath', '//*[@id="kw"]')
    driver_title = browser_driver.get_driver_title()
    print(driver_title)
    browser_driver.if_ctrl(driver_title == "hello world_百度搜索")
    print(browser_driver.flag)
    time.sleep(3)
    browser_driver.quit()